package mapservice;

import geometry.ILocation;
import geometry.IPlace;
import geometry.IRoute;
import geometry.entity.GeometryFactory;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class DirectionsServiceXML {

    // URL prefix to the geocoder
    private static final String DIRECTION_REQUEST_PREFIX_FOR_XML = "http://maps.google.com/maps/api/directions/xml";
    private IRoute route;

    public DirectionsServiceXML() {
        route = GeometryFactory.getRouteInstance();
    }

    /**
     * Get the value of route
     *
     * @return the value of route
     */
    public IRoute getRoute() {
        return route;
    }

    /**
     * Set the value of route
     *
     * @param route new value of route
     */
    public void setRoute(IRoute route) {
        this.route = route;
    }

    public IRoute getDirectionRoute(ILocation Origin, ILocation Destination) throws IOException, XPathExpressionException, ParserConfigurationException, SAXException {
        route.setOrigin((IPlace) Origin);
        route.setDestination((IPlace) Destination);
        return getDirectionRoute(LocationToString(Origin), LocationToString(Destination));
    }

    public IRoute getDirectionRoute(IPlace Origin, IPlace Destination) throws IOException, XPathExpressionException, ParserConfigurationException, SAXException {
        String origin = Origin.toString();
        String destination = Destination.toString();
        route.setOrigin(Origin);
        route.setDestination(Destination);
        return getDirectionRoute(origin, destination);

    }

    public IRoute getDirectionRoute(String origin, String destination) throws IOException, XPathExpressionException, ParserConfigurationException, SAXException {

        String option = "?origin=" + URLEncoder.encode(origin, "UTF-8") + "&destination=" + URLEncoder.encode(destination, "UTF-8");
        URL url = new URL(DIRECTION_REQUEST_PREFIX_FOR_XML + option + "&sensor=false");

        // prepare an HTTP connection to the geocoder
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        Document directionsResultDocument = null;
        try {
            // open the connection and get results as InputSource.
            conn.connect();
            InputSource directionsResultInputSource = new InputSource(conn.getInputStream());

            // read result and parse into XML Document
            directionsResultDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(directionsResultInputSource);
        } finally {
            conn.disconnect();
        }
        return mapXML(directionsResultDocument);

    }

    private IRoute mapXML(Document directionsResultDocument) throws XPathExpressionException {
        // prepare XPath
        float distance=0.0f;
        XPath xpath = XPathFactory.newInstance().newXPath();
        // a) obtain the formatted_address field for every result
        NodeList resultNodeList = (NodeList) xpath.evaluate("/DirectionsResponse/route//start_location/lat", directionsResultDocument, XPathConstants.NODESET);
        for (int i = 0; i < resultNodeList.getLength(); ++i) {
            route.getLeg().put(i, GeometryFactory.getLocationInstance());
            route.getLeg(i).setLat(Float.parseFloat(resultNodeList.item(i).getTextContent()));
        }
        resultNodeList = (NodeList) xpath.evaluate("/DirectionsResponse/route//start_location/lng", directionsResultDocument, XPathConstants.NODESET);
        for (int i = 0; i < resultNodeList.getLength(); ++i) {
            route.getLeg(i).setLng(Float.parseFloat(resultNodeList.item(i).getTextContent()));
        }
        
        resultNodeList = (NodeList) xpath.evaluate("/DirectionsResponse/route//distance/value", directionsResultDocument, XPathConstants.NODESET);
        for (int i = 0; i < resultNodeList.getLength(); ++i) {
          distance+=Float.parseFloat(resultNodeList.item(i).getTextContent());
        }
        route.setDistance(distance);
        
        resultNodeList = (NodeList) xpath.evaluate("/DirectionsResponse/route//end_location/lat", directionsResultDocument, XPathConstants.NODESET);
        route.getLeg().put(resultNodeList.getLength()-1, GeometryFactory.getLocationInstance());
        route.getLeg(resultNodeList.getLength()-1).setLat(Float.parseFloat(resultNodeList.item(resultNodeList.getLength()-1).getTextContent()));
        resultNodeList = (NodeList) xpath.evaluate("/DirectionsResponse/route//end_location/lng", directionsResultDocument, XPathConstants.NODESET);

        route.getLeg(resultNodeList.getLength()-1).setLng(Float.parseFloat(resultNodeList.item(resultNodeList.getLength()-1).getTextContent()));

        return route;
    }

    private String LocationToString(ILocation location) {
        return location.getLat() + "," + location.getLng();
    }

    public final static void main(String[] argv) throws IOException, XPathExpressionException, ParserConfigurationException, SAXException {
    DirectionsServiceXML ds=new DirectionsServiceXML();
       ds.getDirectionRoute("26.039581298828,119.30860137939","26.073837280273,119.33436584473");
    }
}
